#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ruim_ef_codec.h"
//wupeng add begin.
#include "ril_util.h"
//wupeng add end.

unsigned char bcd_arr[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#','*','+', '(', ')', '-' };

#define alarm_if_fail(p) if(!(p)) {printf(""#p" failed.\n");}

static void encode_number_to_bcd(const unsigned char* number, unsigned char* adn_data, int number_len)
{
	const unsigned char* p_num = number;
	unsigned char* p_adn = adn_data;
	char tmp = 0;
	int ni = 0;
	while(ni != number_len)
	{
		/*fill the higher 4 bits*/
		int i = 0;
		for(i=0; i<16; ++i)
		{
			if(bcd_arr[i] ==  *p_num) break;
		}

		*p_adn = i;
		++p_num;
		++ni;
		
		/*and the lower 4bits*/
		if(ni != number_len)
		{
			int i = 0;
			for(i=0; i<16; ++i)
			{
				if(bcd_arr[i] == *p_num) break;
			}

			*p_adn += (i << 4);
			++p_adn;
			++p_num;
			++ni;
		}
		else
		{
			/*the lower unused 4bits has to be filled with f, not 0*/
			*p_adn  += 0xF0;
			break;
		}
	}
	
	return;
}

static void encode_ascii_to_unicode(const unsigned char* asc_data, unsigned char* adn_data, int asc_len)
{
	int i = 0;
	const unsigned char* p_asc = asc_data;
	unsigned char* p_adn = adn_data;
	for(; i<asc_len; i++)
	{
		*p_adn++ = 0x00;
		*p_adn++ = *p_asc++;
	}

	return;
}

static void decode_bcd_number(const unsigned char* bcd_number_data, unsigned char* number, int bcd_len)
{
	int i=0;
	int tmp = 0;
	const unsigned char* p_bcd = bcd_number_data;
	unsigned char* p_number = number;

	for(i=0; i<bcd_len; i++)
	{
		tmp = (*p_bcd) & (0x0F); //get the higher 4 bits
		*p_number++ = bcdToChar(tmp);

		tmp = (*p_bcd) & (0xF0); //get the lower 4 bits
		if(tmp == 0x0F)  /*its a bug?*/
		{
			break;
		}
		*p_number++ = bcdToChar(tmp >> 4);
		p_bcd++;
	}

	return;
}


/*encode pbook struct to EFadn data format*/
int ruim_pbook_encode(const PbookInfo* p_info, unsigned char** efAdnData, int* efAdnDataLen)
{
	//check the input
	if(p_info == NULL || p_info->number == NULL || p_info->text == NULL 
		|| efAdnData == NULL || efAdnDataLen == NULL)
	{
		return 0;
	}
	
	int alpha_len = 0;

	if(p_info->coding == RAW)
	{
		alpha_len = p_info->text_len; /*add 1 because of unicode head 0x80*/
	}
	else if(p_info->coding == ASCII)
	{
		alpha_len = p_info->text_len*2;
	}

	*efAdnDataLen = alpha_len + 14;
	*efAdnData = calloc(1, *efAdnDataLen);
	if(*efAdnData == NULL)
	{
		return 0;
	}
	memset(*efAdnData, 0xFF, *efAdnDataLen);

	unsigned char* p = *efAdnData;
	//copy the text to EFADN alpha field
	//unicode head
	//*p = 0x80;
	if(p_info->coding == RAW)
	{
		memcpy(p, p_info->text, p_info->text_len);
	}
	else if(p_info->coding == ASCII)
	{
		encode_ascii_to_unicode(p_info->text, p, p_info->text_len);
	}
	
	//Length of BCD number/SSC contents
	*(p + alpha_len) = (p_info->number_len + 1) / 2 + 1;

	//TON/NPI
	*(p + alpha_len + 1) = p_info->number_type;

	//dailing number
	encode_number_to_bcd(p_info->number, p+alpha_len+2, p_info->number_len);
	
	//the bytes left is unused.
	//hope we are not out of the buffer
	return 1;
}

int ruim_pbook_decode(const unsigned char* efAdnData, const int efAdnDataLen, PbookInfo* p_info)
{
	const unsigned char* p_data = efAdnData;
	int text_len = 0;
	int i = 0;

	if(efAdnData == NULL || p_info == NULL)
	{
		return 0;
	}

	if(p_data[0] == 0x80) {
		p_data++;
		text_len = efAdnDataLen - 14 - 1;
		p_info->coding = RAW;
		for(i = 0; i < text_len - 1; i+=2) 
		{
			if(p_data[i] == 0xFF && p_data[i + 1] == 0xFF)
			{
				break;
			}
		}
		p_info->text_len = i ;
		p_info->text = (void* )calloc(1, text_len);
		memcpy(p_info->text, p_data, p_info->text_len);
	} else {
		text_len = efAdnDataLen - 14;
		p_info->coding = ASCII;
		p_info->text = (void* )calloc(1, text_len);
		for(i = 0; i < text_len; i++)
		{
			if(p_data[i] == 0xFF)
			{
				break;
			}
		}
		p_info->text_len = i ;
		memcpy(p_info->text, p_data, p_info->text_len);
	}
	
	p_data += text_len;
	p_info->number = (void* )calloc(1, 28);
	if(p_data[0] != 0xFF) 
	{
		int bcd_number_len = *p_data++;
		p_info->number_type = *p_data++;
		decode_bcd_number(p_data, p_info->number, bcd_number_len - 1);
		p_info->number_len = strlen((char*)p_info->number);
	}

	return 1;
}

int ruim_sms_encode(unsigned char status, const unsigned char* pdu, int pdu_len,
		unsigned char** efsms_data, int* efsms_data_len)
{
	if(pdu == NULL || pdu_len <= 0 || efsms_data == NULL || efsms_data_len == NULL)
	{
		return 0;
	}

	//EFsms = status(1 byte) + msg_len(1 byte, pdu_len) + pdu_data(pdu_len)
	//the first byte of pdu is msg_type
	*efsms_data_len = pdu_len + 2;
	*efsms_data = malloc(*efsms_data_len);
	if(*efsms_data == NULL)
	{
		return 0;
	}

	unsigned char* p = *efsms_data;
	
	*p++ = status;
	*p++ = pdu_len;
	memcpy(p, pdu, pdu_len);

	return 1;	
}

int ruim_sms_decode(const unsigned char* efsms_data, int efsms_data_len, 
		unsigned char* status, unsigned char** pdu, int* pdu_len)
{
	if(efsms_data_len <= 0 || efsms_data == NULL || 
		status == NULL || pdu == NULL || pdu_len == NULL)
	{
		return 0;
	}
	
	//EFsms = status(1 byte) + msg_len(1 byte, pdu_len) + pdu_data(pdu_len)
	*pdu_len = efsms_data_len - 2;
	*pdu = malloc(*pdu_len);
	if(pdu == NULL)
	{
		return 0;
	}

	const unsigned char* p = efsms_data;
	*status = *p++;
	*p++;  //msg_len
	memcpy(*pdu, p, *pdu_len);
	
	return 1;
}

#ifdef _UT_TEST

void test_encode_number_to_bcd()
{
	unsigned char a[100] = {"123456789"};
	unsigned char b[100] = {0};
	encode_number_to_bcd(a, b, 9);
	alarm_if_fail(b[0] == 0x12);
	alarm_if_fail(b[1] == 0x34);
	alarm_if_fail(b[2] == 0x56);
	alarm_if_fail(b[3] == 0x78);
	alarm_if_fail(b[4] == 0x9f);
	
}

void test_encode_ascii_to_unicode()
{
	unsigned char a[100] = {"abcdefg"};
	unsigned char b[100] = {0};
	encode_ascii_to_unicode(a, b, 7);
	alarm_if_fail(b[0] == 0x00);
	alarm_if_fail(b[1] == 'a');
	alarm_if_fail(b[2] == 0x00);
	alarm_if_fail(b[3] == 'b');
	alarm_if_fail(b[4] == 0x00);
	alarm_if_fail(b[5] == 'c');
	alarm_if_fail(b[6] == 0x00);
	alarm_if_fail(b[7] == 'd');
	alarm_if_fail(b[8] == 0x00);
	alarm_if_fail(b[9] == 'e');
	alarm_if_fail(b[10] == 0x00);
	alarm_if_fail(b[11] == 'f');
	alarm_if_fail(b[12] == 0x00);
	alarm_if_fail(b[13] == 'g');
}

void test_decode_bcd_number()
{
	unsigned char a[100] = {0x12,0x34,0x56,0x78, 0x9F};
	char b[100] = {0};
	decode_bcd_number(a, b, 5);
	alarm_if_fail(b[0] == '1');
	alarm_if_fail(b[1] == '2');
	alarm_if_fail(b[2] == '3');
	alarm_if_fail(b[3] == '4');
	alarm_if_fail(b[4] == '5');
	alarm_if_fail(b[5] == '6');
	alarm_if_fail(b[6] == '7');
	alarm_if_fail(b[7] == '8');
	alarm_if_fail(b[8] == '9');
}

void test_ruim_pbook_encode_decode()
{
	PbookInfo info;
	info.text = "abcdefg";
	info.number = "15996243145";
	info.text_len = 7;
	info.number_len = 11;
	info.coding = ASCII;
	info.number_type = 0x11;
	unsigned char* encode_data = NULL;
	int data_len = 0;

	ruim_pbook_encode(&info, &encode_data, &data_len);
	
	alarm_if_fail(data_len == 29);
	alarm_if_fail(encode_data[0] == 0x80);
	alarm_if_fail(encode_data[1] == 0x00);
	alarm_if_fail(encode_data[2] == 'a');
	alarm_if_fail(encode_data[3] == 0x00);
	alarm_if_fail(encode_data[4] == 'b');
	alarm_if_fail(encode_data[5] == 0x00);
	alarm_if_fail(encode_data[6] == 'c');
	alarm_if_fail(encode_data[7] == 0x00);
	alarm_if_fail(encode_data[8] == 'd');
	alarm_if_fail(encode_data[9] == 0x00);
	alarm_if_fail(encode_data[10] == 'e');
	alarm_if_fail(encode_data[11] == 0x00);
	alarm_if_fail(encode_data[12] == 'f');
	alarm_if_fail(encode_data[13] == 0x00);
	alarm_if_fail(encode_data[14] == 'g');
	alarm_if_fail(encode_data[15] == 6);
	alarm_if_fail(encode_data[16] == 0x11);
	alarm_if_fail(encode_data[17] == 0x15);
	alarm_if_fail(encode_data[18] == 0x99);
	alarm_if_fail(encode_data[19] == 0x62);
	alarm_if_fail(encode_data[20] == 0x43);
	alarm_if_fail(encode_data[21] == 0x14);

	alarm_if_fail(encode_data[22] == 0x5f);
	alarm_if_fail(encode_data[23] == 0xff);

	PbookInfo info2 = {0};
	ruim_pbook_decode(encode_data, data_len, &info2);
	unsigned char* text = info2.text;
	alarm_if_fail(text[1] == 'a');
	alarm_if_fail(text[3] == 'b');
	alarm_if_fail(text[5] == 'c');
	alarm_if_fail(text[7] == 'd');
	alarm_if_fail(text[9] == 'e');
	alarm_if_fail(text[11] == 'f');
	alarm_if_fail(text[13] == 'g');
	
	alarm_if_fail(strcmp(info2.number, "15996243145") == 0);
	alarm_if_fail(info2.coding == RAW);
	alarm_if_fail(info2.number_type == 0x11);
	alarm_if_fail(info2.number_len == 11);
	
	free(encode_data);
	free(info2.text);
	free(info2.number);
}

void test_sms_decode_encode()
{
	unsigned char* pdu = "f1234567890";
	int pdu_len = 11;
	unsigned char* efsms_data = NULL;
	int efsms_data_len = 0;
	unsigned char status = 0x02;

	ruim_sms_encode(status, pdu, pdu_len, &efsms_data, &efsms_data_len);
	puts(efsms_data);
	alarm_if_fail(efsms_data_len == 13);
	
	ruim_sms_decode(efsms_data, efsms_data_len, &status, &pdu, &pdu_len);
	puts(pdu);
	alarm_if_fail(status == 0x02);
	alarm_if_fail(pdu_len == 11);

	free(efsms_data);
	free(pdu);

	return;
}

int main(int argc, char** argv)
{
	test_encode_number_to_bcd();
	test_encode_ascii_to_unicode();
	test_decode_bcd_number();
	test_ruim_pbook_encode_decode();
	test_sms_decode_encode();
	return 0;
}

#endif
